suite("defineType", function () {
    "use strict";

    var defineType = require("./define-type");
    var assert = require("assert");

    test("no proto", function () {
        var Type = defineType(function (a) {
            this.a = a;
        });
        var instance = new Type(1);
        assert(instance.a === 1);
    });

    test("empty ctor, proto", function () {
        var Type = defineType(function() {}, {});
        var instance = new Type;
        for (var name in instance) {
            assert(false);
        }
    });

    test("ctor, proto", function () {
        var Type = defineType(function (a, b) {
            this.a = a;
            this.b = b;
        }, {
            a: 0,
            b: 1,
            c: 2
        });
        var instance = new Type(11, 12);
        assert(instance.a === 11);
        assert(instance.b === 12);
        assert(instance.c === 2);
    });

    test("multiple levels, mixins, overrides", function () {
        var Type = defineType(function (a, b) {
            this.a = a;
            this.b = b;
        }, {
            a: 0,
            b: 1,
            c: 2,
        });

        var Format = defineType({
            formatToString: function () {
                return "the value is: " + this.formatValue() + ".";
            },
            formatValue: function () {
                return undefined;
            }
        });

        var DateMilliseconds = defineType(function () {
            this.value = new Date().valueOf();
        }, {
            valueInMilliseconds: function () {
                return this.value;
            }
        });

        var DateSeconds = defineType({
            valueInSeconds: function () {
                return this.valueInMilliseconds() / 1000;
            }
        }, new DateMilliseconds);

        var DateMinutes = defineType(new Type(3, 4),
            new Format, new DateSeconds, {
            valueInMinutes: function () {
                return this.valueInSeconds() / 60;
            },
            formatValue: function () {
                return this.valueInMinutes();
            }
        });

        var instance = new DateMinutes(11, 12);
        assert(instance.a === 11);
        assert(instance.b === 12);
        assert(instance.c === 2);
        assert(instance.formatToString() ===
            "the value is: " + ((instance.value / 1000) / 60) + ".");
    });

    test("instance of derived", function () {
        var Type0 = function () {};
        var Type1 = defineType(new Type0);
        var instance = new Type1;
        assert(instance instanceof Type0);
    });

    test("all constructors called", function () {
        var A = defineType(function () {
            aCalled = true;
        }, {
            a: 1
        });

        var B = defineType(function () {
            bCalled = true;
        }, {
            b: 2
        });

        var C = defineType(function () {
            cCalled = true;
        }, new A, new B);

        var D = defineType(function () {
            dCalled = true;
        }, new C, {
            d: 3
        });

        var aCalled = false;
        var bCalled = false;
        var cCalled = false;
        var dCalled = false;

        new D;
        assert(aCalled && bCalled && cCalled && dCalled);
    });

    test("constructor order", function () {
        var order = [];

        var A = defineType(function () {
            order.push("a");
        });

        var B = defineType(function () {
            order.push("b");
        }, new A);

        var C = defineType(function () {
            order.push("c");
        }, new B);

        order.length = 0;
        new C;
        assert(order[0] === "a");
        assert(order[1] === "b");
        assert(order[2] === "c");
    });
});
